<?php
namespace Framework\Library\Core;

/**
 * 表单处理基础类 ,实现了基本的表单数据检查功能 
 * 
 * 如果当前请求为post方式，那么本类会自动从请求中读取表单数据，并用DataVerify对象检查表单数据的正确性。
 * 如果所有的表单域都通过了，那么ready方法可返回true，表明表单数据可以提交致数据了
 */
abstract class Form{
	
	/**
	 * 表单域列表，域名称作为数组键名，数据检查类型作为数组键值
	 * @var array
	 */
	protected $fields;
	
	/**
	 * 对应于fields属性的各个表单域的值
	 * @var array
	 */
	protected $datas;
	
	/**
	 * 用于指定验证条件的值
	 * @var array
	 */
	protected $verifys;
	
	/**
	 * 表单各域的处理的结果状态
	 * @var array
	 */
	protected $states;
	
	/**
	 * DataVerify对象
	 * @var DataVerify
	 */
	protected $dataVerify;
	
	protected $module;

	public $state = self::STATE_INIT;
	
	const STATE_INIT = 0;
	const STATE_SAVED = 1;
	const STATE_VERIFY_FAIL = -1;
	const STATE_SAVE_FAIL = -2;
	
	function __construct( $module, $fields, $verifys ) {
		
		$this->module = $module;
		
		$this->fields = $fields;
		$this->verifys = $verifys;
		
		$this->datas = array();
		$this->states = array();
		
		require_once __DIR__.'/../Utility/DataVerify.class.php';
		$this ->dataVerify = new \Framework\Library\Utility\DataVerify();
		
		if ($this->module ->isPost()){
			
			$this->process();
			if ($this->ready()) $this->save();
			
		}
		
	}
	
	abstract protected function save();
	
	/**
	 * 检查表单数据
	 */
	private function process(){
		
		foreach ($this->fields as $field =>$type){
			
			if ($type=='POST') $data_var = $_POST;
			else if ($type=='FILES') $data_var = $_FILES;
			else throw new \Exception('未知的变量类型');
			
			$data = $data_var[$field];
			
			$this->datas[$field] = $data;
			
			if ($type == 'POST'){
				$this->verifyPostField($field);
			}else if ($type == 'FILES') {
				$this->verifyFilesField($field);
			}else throw new \Exception("未知的表单域类型$type");
			
		}
		
		if (!$this->ready()) $this->state = self::STATE_VERIFY_FAIL;
		
	}
	
	/**
	 * 检查POST类型的表单域
	 * @param string $field
	 * @return void
	 */
	private function verifyPostField($field){
		
		if (!empty($this->verifys[$field])){
			
			foreach ($this->verifys[$field] as $method =>$params){
				
				if (empty($params)) $params = NULL;
				
				$msg = NULL;
				$state = $this->dataVerify ->$method($this->datas[$field],$params,$msg);
				
				$this->states[$field][$method] = array('state'=>$state,'msg'=>$msg);
				
			}
			
		}
		
	}
	
	/**
	 * 检查FILES类型的表单域
	 * @param string $field
	 * @return void
	 */
	private function verifyFilesField($field){
		
		if (!empty($this->verifys[$field])){
			
			$data = $this->datas[$field];
			
			$this->states[$field] = array();
				
			foreach ($this->verifys[$field] as $method =>$params){
				
				if (empty($params)) $params = NULL;
				
				if (is_array($data['error'])){
					
					$msg = array();
					$state = array();
					
					foreach ($data['error'] as $error){
						
						if ($error !== UPLOAD_ERR_OK){
							
							array_push($msg,'文件没有上传成功');
							array_push($state,false);
							
						}else{
							
							$tmp_msg = NULL;
							$tmp_state = $this->dataVerify ->$method($data['tmp_name'],$params,$tmp_msg);
							
							array_push($msg,$tmp_msg);
							array_push($state,$tmp_state);
							
						}
						
					}
					
				}else{
					
					$msg = NULL;
					$state = NULL;
					
					if ($data['error'] !== UPLOAD_ERR_OK){
							
						$msg = '文件没有上传成功';
						$state = false;
							
					}else{
							
						if (empty($params)) $params = NULL;
						$state = $this->dataVerify ->$method($data['tmp_name'],$params,$msg);
							
					}
					
				}
		
				$this->states[$field][$method] = array('state'=>$state,'msg'=>$msg);
		
			}
				
		}
		
	}
	
	/**
	 * 表单是否已准备好提交致数据库
	 * 
	 * 检查表单处理states属性，如果全部域的检查都通过，那么就返回true，否则返回false
	 * @return bool
	 */
	public function ready(){
		
		if (empty($this->states)) return false;
		
		foreach ($this->states as $field_state){
			
			foreach ($field_state as $field_state_item){
				
				if (is_array($field_state_item['state'])){
					
					foreach ($field_state_item['state'] as $state){
						if (!$state) return false;
					}
					
				}else{
					
					if (!$field_state_item['state']) return false;
					
				}
					
			}
			
		}
		
		return true;
		
	}
	
	public function getFieldData( $field_name = NULL ){
		
		if ($field_name === NULL) return $this->datas;
		return $this->datas[$field_name];
		
	}
	
	public function getFieldState( $field_name = NULL ){
		
		if ($field_name === NULL) return $this->states;
		return $this->states[$field_name];
		
	}
	
}